﻿/**
 * Copyright (C) 2012-2013 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NGuice.Inject.Spi;
using NGuice.Inject.Internal.Util;
using NGuice.Inject.Matcher;
using System.Reflection;
using AopAlliance.Intercept;

namespace NGuice.Inject.Internal
{
    internal sealed class EncounterImpl<T> : ITypeEncounter<T>
    {
        private readonly Errors errors;
        private readonly ILookups lookups;

        //通常认为一个注入器包含的可注入成员是泛型参数T的子类，但事实并非如此。这个问题和依赖倒置一样，
        //可注入器包含的成员注入列表，是泛型T参数的超类！因为只有超类成员，才允许子类T的注入赋值！
        private List<IMembersInjector> membersInjectors; // lazy 成员必须是IMembersInjector<? super T>即泛型参数必须是T的超类类型
        private List<InjectionListener> injectionListeners; // lazy 成员必须是IMembersInjector<? super T>即泛型参数必须是T的超类类型
        /*if[AOP]*/
        private List<MethodAspect> aspects; // lazy
        /*end[AOP]*/
        private bool valid = true;

        internal EncounterImpl(Errors errors, ILookups lookups)
        {
            this.errors = errors;
            this.lookups = lookups;
        }

        internal void Invalidate()
        {
            valid = false;
        }

        /*if[AOP]*/
        internal ImmutableList<MethodAspect> Aspects
        {
            get
            {
                return aspects == null
                    ? ImmutableList<MethodAspect>.Of()
                    : ImmutableList<MethodAspect>.CopyOf<MethodAspect>(aspects);
            }
        }

        public void BindInterceptor(IMatcher methodMatcher, params IMethodInterceptor[] interceptors)
        {
            Preconditions.CheckState(valid, "Encounters may not be used after hear() returns.");
            Preconditions.CheckSuperGenericParameter<MethodInfo>(methodMatcher);
            // make sure the applicable aspects is mutable
            if (aspects == null)
            {
                aspects = Lists.NewArrayList<MethodAspect>();
            }

            aspects.Add(new MethodAspect(Matchers.Any(), methodMatcher, interceptors));
        }
        /*end[AOP]*/

        /// <summary>
        /// 列表中的的成员必须是IMembersInjector泛型成员，且泛型参数必须是T的超类
        /// </summary>
        internal ImmutableList<IMembersInjector> MembersInjectors
        {
            get
            {
                return membersInjectors == null
                    ? ImmutableList<IMembersInjector>.Of()
                    : ImmutableList<IMembersInjector>.CopyOf<IMembersInjector>(membersInjectors);
            }
        }

        /// <summary>
        /// 列表中的的成员必须是InjectionListener泛型成员，且泛型参数必须是T的超类
        /// </summary>
        /// <returns></returns>
        internal ImmutableList<InjectionListener> InjectionListeners
        {
            get
            {
                return injectionListeners == null
                    ? ImmutableList<InjectionListener>.Of()
                    : ImmutableList<InjectionListener>.CopyOf<InjectionListener>(injectionListeners);
            }
        }

        public void Register(IMembersInjector membersInjector)
        {
            Preconditions.CheckState(valid, "Encounters may not be used after hear() returns.");
            Preconditions.CheckSuperGenericParameter<T>(membersInjector);
            if (membersInjectors == null)
            {
                membersInjectors = Lists.NewArrayList<IMembersInjector>();
            }

            membersInjectors.Add(membersInjector);
        }

        public void Register(InjectionListener injectionListener)
        {
            Preconditions.CheckState(valid, "Encounters may not be used after hear() returns.");
            Preconditions.CheckSuperGenericParameter<T>(injectionListener);
            if (injectionListeners == null)
            {
                injectionListeners = Lists.NewArrayList<InjectionListener>();
            }

            injectionListeners.Add(injectionListener);
        }

        public void AddError(string message, params object[] arguments)
        {
            Preconditions.CheckState(valid, "Encounters may not be used after hear() returns.");
            errors.AddMessage(message, arguments);
        }

        public void AddError(Exception t)
        {
            Preconditions.CheckState(valid, "Encounters may not be used after hear() returns.");
            errors.ErrorInUserCode(t, string.Format("An exception was caught and reported. Message: {0}", t.Message));
        }

        public void AddError(Message message)
        {
            Preconditions.CheckState(valid, "Encounters may not be used after hear() returns.");
            errors.AddMessage(message);
        }

        public IProvider<T> GetProvider<T>(Key<T> key)
        {
            Preconditions.CheckState(valid, "Encounters may not be used after hear() returns.");
            return lookups.GetProvider(key);
        }

        public IProvider<T> GetProvider<T>()
        {
            return GetProvider(Key<T>.Get());
        }

        public IMembersInjector<T> GetMembersInjector<T>()
        {
            Preconditions.CheckState(valid, "Encounters may not be used after hear() returns.");
            return lookups.GetMembersInjector<T>();
        }

    }
}
